package com.gy.Task;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.ListObjectsRequest;
import com.aliyun.oss.model.ObjectListing;
import com.gy.properties.AliOssProperties;
import jakarta.annotation.PreDestroy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.jdbc.core.JdbcTemplate;


import java.security.NoSuchAlgorithmException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import java.security.MessageDigest;
@Component
public class OssFileScanner {
    private static final Logger logger = LoggerFactory.getLogger(OssFileScanner.class);
    private final AliOssProperties aliOssProperties;
    private final JdbcTemplate jdbcTemplate;
    private final OSS ossClient;

    private static final String SQL_QUERY = "SELECT pdf_path FROM result_papers WHERE pdf_path IS NOT NULL " +
            "UNION ALL " +
            "SELECT pdf_url FROM result_other WHERE pdf_url IS NOT NULL " +
            "UNION ALL " +
            "SELECT pdf_url FROM result_patents WHERE pdf_url IS NOT NULL " +
            "UNION ALL " +
            "SELECT pdf_url FROM result_personal_award WHERE pdf_url IS NOT NULL " +
            "UNION ALL " +
            "SELECT pdf_url FROM result_publication WHERE pdf_url IS NOT NULL " +
            "UNION ALL " +
            "SELECT pdf_url FROM result_report WHERE pdf_url IS NOT NULL " +
            "UNION ALL " +
            "SELECT pdf_url FROM result_student_award WHERE pdf_url IS NOT NULL " +
            "UNION ALL " +
            "SELECT pdf_url FROM result_certificateinfo WHERE pdf_url IS NOT NULL " +
            "UNION ALL " +
            "SELECT pdf_url FROM result_continuing_education_material WHERE pdf_url IS NOT NULL " +
            "UNION ALL " +
            "SELECT pdf_url FROM result_copyright WHERE pdf_url IS NOT NULL";

    @Autowired
    public OssFileScanner(AliOssProperties aliOssProperties, JdbcTemplate jdbcTemplate) {
        this.aliOssProperties = aliOssProperties;
        this.jdbcTemplate = jdbcTemplate;
        this.ossClient = new OSSClientBuilder().build(
                aliOssProperties.getEndpoint(),
                aliOssProperties.getAccessKeyId(),
                aliOssProperties.getAccessKeySecret()
        );
    }

    @Scheduled(cron = "0 0 0 */3 * ?") // 每三天执行一次
    public void scanAndDeleteUnusedFiles() {
        int batchSize = 1000;
        String countSql = "SELECT COUNT(*) FROM (" + SQL_QUERY + ") AS combined";
        int totalCount = jdbcTemplate.queryForObject(countSql, Integer.class);

        // 分批次查询文件路径并计算哈希值
        for (int offset = 0; offset < totalCount; offset += batchSize) {
            String sql = SQL_QUERY + " LIMIT ? OFFSET ?";
            List<String> pdfPathsInDb = jdbcTemplate.queryForList(sql, String.class, batchSize, offset);

            // 使用并行流计算 SHA-256 哈希值
            Set<String> pdfKeysInDb = pdfPathsInDb.parallelStream()
                    .map(this::generateSHA256)
                    .collect(Collectors.toSet());

            // 异步扫描OSS并对比哈希值
            CompletableFuture.runAsync(() -> scanAndDeleteFiles(pdfKeysInDb));
        }
    }

    private String generateSHA256(String filePath) {
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] hashBytes = digest.digest(filePath.getBytes());
            StringBuilder hexString = new StringBuilder();
            for (byte b : hashBytes) {
                hexString.append(String.format("%02x", b));
            }
            return hexString.toString();
        } catch (NoSuchAlgorithmException e) {
            logger.error("Error generating SHA-256 hash: {}", e.getMessage());
            return null;
        }
    }

    @Async
    public void scanAndDeleteFiles(Set<String> pdfKeysInDb) {
        ListObjectsRequest listObjectsRequest = new ListObjectsRequest(aliOssProperties.getBucketName());
        listObjectsRequest.setMaxKeys(1000);

        String marker = null;
        ObjectListing objectListing;
        do {
            if (marker != null) {
                listObjectsRequest.setMarker(marker);
            }
            objectListing = ossClient.listObjects(listObjectsRequest);

            objectListing.getObjectSummaries().forEach(objectSummary -> {
                String fileName = objectSummary.getKey();
                if (fileName.toLowerCase().endsWith(".pdf")) {
                    String fileHash = generateSHA256(fileName);
                    if (!pdfKeysInDb.contains(fileHash)) {
                        logger.info("Deleting unused file: {}", fileName);
                        try {
                            ossClient.deleteObject(aliOssProperties.getBucketName(), fileName);
                        } catch (Exception e) {
                            logger.error("Error deleting file from OSS: {}", fileName, e);
                        }
                    }
                }
            });

            marker = objectListing.getNextMarker();
        } while (objectListing.isTruncated());
    }

    @PreDestroy
    public void cleanup() {
        try {
            if (ossClient != null) {
                ossClient.shutdown();
                logger.info("OSS client has been shut down.");
            }
        } catch (Exception e) {
            logger.error("Error while shutting down OSS client: {}", e.getMessage());
        }
    }
}
